/*
 * AnimationEngine.java
 *
 * Created on October 28, 2007, 4:17 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package simulationengine.animation;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
//import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 *
 * @author edrucker
 */
public class AnimationEngine extends JFrame implements Runnable
{
	private int animationClock;
	private int maxTime;
	private int[]  serviceLocations;
	private int numServices;

	private int[] numInQueue;
	
	//private LinkedBlockingQueue<AnimationCommand> commands;
        private PriorityBlockingQueue<AnimationCommand> commands;
	private ArrayList<AnimationObject> currentObjects = new ArrayList<AnimationObject>();
	
	private JLabel clockLabel = new JLabel("Animation Time: ");
	
	private final Thread displayer;
	
	
	public class DisplayPanel extends JPanel
	{
		
		public DisplayPanel()
		{
			clockLabel.setLocation(10, 10);
			add(clockLabel);
		}
		
		public void paintComponent(Graphics gr)
		{
			super.paintComponent(gr);
			Graphics2D gr2 = (Graphics2D)gr;
			
			
			
			int xOffset = 50;
			int yBase = 200;
			
			for(int i = 0; i < serviceLocations.length; i++)
			{
				//motion line before queue
				gr2.setColor(Color.RED);
				gr2.draw(new Line2D.Double(xOffset, yBase, xOffset+50, yBase));
				xOffset += 50;
				
				//queue
				gr2.setColor(Color.BLUE);
				gr2.draw(new Rectangle2D.Double(xOffset, yBase-25, 200, 50));
				xOffset += 200;
				
				//motion line before service
				gr2.setColor(Color.RED);
				gr2.draw(new Line2D.Double(xOffset, yBase, xOffset+50, yBase));
				xOffset += 50;
				
				//service
				int rectHeight = 50 * serviceLocations[i];
				int yOffset = rectHeight/2;
				
				gr2.setColor(Color.GREEN);
				gr2.draw(new Rectangle2D.Double(xOffset, yBase-yOffset, 50, rectHeight));
				xOffset += 50;
			}	
			//final motion line
			gr2.setColor(Color.RED);
			gr2.draw(new Line2D.Double(xOffset, yBase, xOffset+50, yBase));
			xOffset += 50;
			
			
			//add objects to stage
			for(int i = 0; i < currentObjects.size(); i++)
			{
				gr2.setColor(Color.YELLOW);
				gr2.fill(new Ellipse2D.Double(currentObjects.get(i).getX(), currentObjects.get(i).getY(), 40, 40));
			}
				
		}
	}
	
	
	/** Creates a new instance of AnimationEngine */
	public AnimationEngine(String title, PriorityBlockingQueue<AnimationCommand> commands, int maxTime, int [] serviceLocations)
	{
		super(title);
		setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
		
		this.commands = commands;
		this.maxTime = maxTime;
		this.serviceLocations = serviceLocations;
		
		numInQueue = new int[serviceLocations.length];
		Arrays.fill(numInQueue, 0);
		
		add(new DisplayPanel());
		setLocation(100, 100);
		setSize(1000, 450);
		setVisible(true);
		
		
		
		displayer = new Thread(this, "displayer");
		displayer.start();
	}

	public void run()
	{
		//setup field
		numServices = serviceLocations.length;
		
	//	commands.add(new AnimationCommand(AnimationCommand.Command.ADD, 0, 0, 0, 0));
	//	commands.add(new AnimationCommand(AnimationCommand.Command.ADD, 1, 1, 1, 0));
	//	commands.add(new AnimationCommand(AnimationCommand.Command.ADD, 2, 2, 2, 0));
	//	commands.add(new AnimationCommand(AnimationCommand.Command.BEGIN_SERVICE, 4, 0, 0, 0));
	//	commands.add(new AnimationCommand(AnimationCommand.Command.END_SERVICE, 10, 0, 0, 0));
		
		//start animation
		animationClock = 0;
		
		while(animationClock < maxTime)
		{
                    //System.out.println( (commands.peek()!=null) + " " + commands.peek().getTime() + " " + animationClock);
			while(commands.peek() != null && commands.peek().getTime() <= animationClock)
			{
				AnimationCommand nextCommand = commands.poll();
                                /*try{ nextCommand = commands.take(); }
                                    catch(InterruptedException e)
                                        { 
                                            System.out.println("Interrupted while taking next command"); 
                                            return;
                                        }
                                  */  
				
				if(nextCommand.getCommand() == AnimationCommand.Command.ADD)
				{
					add(nextCommand);
				}
				else if(nextCommand.getCommand() == AnimationCommand.Command.BEGIN_SERVICE)
				{
					beginService(nextCommand);
				}
				else if(nextCommand.getCommand() == AnimationCommand.Command.END_SERVICE)
				{
					endService(nextCommand);
				}
				else if(nextCommand.getCommand() == AnimationCommand.Command.REMOVE)
				{
					remove(nextCommand);
				}
				else if(nextCommand.getCommand() == AnimationCommand.Command.RETURN_TO_BEGINNING)
				{
					returnToBeginning(nextCommand);
				}
			}
			
			repaint();
			
			
			try
			{
				displayer.sleep(10);
			} catch(InterruptedException e) {}
			
			animationClock++;
			clockLabel.setText("Animation Time: " + animationClock);
		}
	}
	
	private void add(AnimationCommand command)
	{
		AnimationObject object = new AnimationObject(command.getID());
		object.setX(30);
		object.setY(180);
		object.setStatus(AnimationObject.Status.IN_QUEUE);
		object.setStatusModifier(0);
		
		currentObjects.add(object);
		int index = currentObjects.size() - 1;
		
		numInQueue[0]++;
		
		int x = 30;
		while(x < 80)
		{
			x++;
			currentObjects.get(index).setX(x);
			try
		{
			displayer.sleep(5);
		} catch (InterruptedException ex)
		{
			ex.printStackTrace();
		}
			repaint();
		}
		
		//place into queue
		x = 300 - (numInQueue[0] * 50);
		currentObjects.get(index).setX(x);
		
		
		repaint();
	}
	
	private void beginService(AnimationCommand command)
	{
		int index = 0;
		
		for(int i = 0; i < currentObjects.size(); i++)
		{
			if(currentObjects.get(i).getID() == command.getID())
			{
				index = i;
				break;
			}
		}
		
		int x = 50 + (command.getStepNum() * 350) + 230;
		int stop = x + 50;
		
		while(x < stop)
		{
			x++;
                        if(index < currentObjects.size())
                            currentObjects.get(index).setX(x);
			try
		{
			displayer.sleep(10);
		} catch (InterruptedException ex)
		{
			ex.printStackTrace();
		}
			repaint();
		}
		
		//place into queue
		x = 50 + (command.getStepNum() * 350) + 300 + 5;
                if(index < currentObjects.size())
                    currentObjects.get(index).setX(x);
		int y = 200-((serviceLocations[command.getStepNum()] *50)/2) + command.getResourceNum()*50 + 5;
                if(index < currentObjects.size())
                    currentObjects.get(index).setY(y);
		
		
		repaint();
		
		numInQueue[0]--;
		
	}
	
	private void endService(AnimationCommand command)
	{
		
		int index = 0;
		
		for(int i = 0; i < currentObjects.size(); i++)
		{
			if(currentObjects.get(i).getID() == command.getID())
			{
				index = i;
				break;
			}
		}
		
		int x = 50 + (command.getStepNum() * 350) + 330;
		int stop = x + 50;
		
		while(x < stop)
		{
			x++;
                        if(index < currentObjects.size())
                            currentObjects.get(index).setX(x);
			try
		{
			displayer.sleep(10);
		} catch (InterruptedException ex)
		{
			ex.printStackTrace();
		}
			repaint();
		}
		
		
		if(command.getStepNum() + 1 < numServices)
		{
			
		}
		
		else
		{
                        if(index < currentObjects.size())
                            currentObjects.remove(index);
		}
	}
	
	private void remove(AnimationCommand command)
	{
		
	}
	
	private void returnToBeginning(AnimationCommand command)
	{
		
	}
	
}
